package com.example.myserver.util.qrcode;

import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.example.myserver.common.exception.InternalServerException;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;


/**
 * 生成带标题, 二维码和标签文字的铭牌
 * ______________________________________
 * |        QRCodeLabel.title           |
 * |  QRCodeMatrix  QRCodeLabel.item_1  |
 * |  QRCodeMatrix  QRCodeLabel.item_2  |
 * |  QRCodeMatrix  QRCodeLabel.item_3  |
 * |------------------------------------|
 */
public final class LabeledQRCode {

    private final String text;

    private final QRCodeLabel label;

    private Path tempBase;

    private BufferedImage bufferedImage;

    private final int width = 1000;

    private final int height = 1000;

    public static final Path QRCODE_TEMP_PATH =
            Paths.get(System.getProperty("user.dir")).resolve("workspace").resolve("qrCodes");

    static {
        try {
            if (Files.notExists(QRCODE_TEMP_PATH)) {
                Files.createDirectories(QRCODE_TEMP_PATH);
            }
        } catch (IOException e) {
            throw new InternalServerException("初始化默认目录失败");
        }
    }
    
    private LabeledQRCode(final String text, final QRCodeLabel label) {
        this.text = text;
        this.label = label;
    }

    public static LabeledQRCode of(final String text, final QRCodeLabel label) {
        return new LabeledQRCode(text, label);
    }

    public LabeledQRCode withTempBase(final Path tempBase) {
        this.tempBase = tempBase;
        return this;
    }

    public Path toFile(final String name) {
        try {
            final File file = createTempFile(name);
            ImageIO.write(drawLabels().toBufferedImage(), "png", file);
            return file.toPath();
        } catch (IOException e) {
            e.printStackTrace();
            throw new InternalServerException("Failed to create QR image from text due to underlying exception", e);
        }
    }

    public BufferedImage toBufferedImage() {
        return this.bufferedImage;
    }

    public LabeledQRCode drawLabels() {
        final BufferedImage image = getBufferedImage();
        final Graphics2D graphics2D = createGraphics(image);
        try {
            drawLabelTitle(graphics2D);
        } finally {
            graphics2D.dispose();
        }
        return this;
    }

    private Graphics2D createGraphics(final BufferedImage image) {
        final Graphics2D graphics2D = image.createGraphics();
        graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        graphics2D.setColor(Color.WHITE);
        graphics2D.fillRect(0, 0, width, height);
        return graphics2D;
    }

    private void drawLabelTitle(final Graphics2D graphics) {
        final Font font = new Font("黑体", Font.BOLD, 40);
        graphics.setFont(font);
        graphics.setColor(Color.BLACK);
        
        // 绘制二维码
        final BufferedImage image = getBufferedImage();
        final int qrCodeLength = 600;
        final Graphics codePic = image.getGraphics();
        final BufferedImage codeImg;
        final QrConfig config = new QrConfig();
        config.setWidth(qrCodeLength);
        config.setHeight(qrCodeLength);
        codeImg = QrCodeUtil.generate(text, config);

        final List<String> rowValues = getRowValues(graphics);
        final int topQrcode = 30;
        final int contentHeight = rowValues.size() * 42 + qrCodeLength + topQrcode;
        final int offsetHeight = height - contentHeight;
        
        // 二维码居中绘制
        final int qrX = (width - qrCodeLength) / 2;
        final int qrY = offsetHeight / 2; // 二维码距离顶部留白
        graphics.drawImage(codeImg, qrX, qrY, qrCodeLength, qrCodeLength, null);

        // 2. 设置 offsetY 为二维码下方
        int offsetY = qrY + qrCodeLength + topQrcode; // 二维码下方留白 topQrcode 像素
        
        for (final String rowValue : rowValues) {
            /*graphics.drawString(rowValue,
                    (width - graphics.getFontMetrics().stringWidth(rowValue)) / 2, offsetY);*/
            graphics.drawString(rowValue, 240, offsetY);
            offsetY += 42;
        }

        codePic.dispose();
    }

    private List<String> getRowValues(Graphics2D graphics) {
        final int maxWidth = 500;
        final List<String> rowValues = new ArrayList<>();
        final String  strContent = label.title;
        StringBuilder line = new StringBuilder();
        for (int i = 0; i < strContent.length(); i++) {
            char c = strContent.charAt(i);
            line.append(c);
            final int lineWidth = graphics.getFontMetrics().stringWidth(line.toString());
            if (lineWidth > maxWidth || c == '\n') {
                // 遇到换行符或超过宽度，绘制当前行
                if (c == '\n') {
                    // 如果是换行符，去掉它
                    line.deleteCharAt(line.length() - 1);
                }
                rowValues.add(line.toString());
                line = new StringBuilder();
            }
        }
        if (line.length() > 0) {
            rowValues.add(line.toString());
        }
        
        return rowValues;
    }

    private BufferedImage getBufferedImage() {
        if (Objects.isNull(bufferedImage)) {
            bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        }
        return bufferedImage;
    }

    private File createTempFile(final String name) throws IOException {
        final String defaultName = Objects.isNull(name)
            ? UUID.randomUUID().toString().replaceAll("-", "") : name;
        if (Objects.isNull(tempBase)) {
            final File file = File.createTempFile(defaultName, ".png");
            file.deleteOnExit();
            return file;
        }
        final Path path = tempBase.resolve(defaultName + ".png");
        return Files.createFile(path).toFile();
    }

    public static class QRCodeLabel {

        private final String title;

        public QRCodeLabel(final String title) {
            this.title = title;
        }
    }
   
    
    public static void main(String[] args) {
        final String title = "/化工厂区/公辅项目分部/220千伏总变电站外线路…/一单元/地管" ;
        final QRCodeLabel label = new QRCodeLabel(title);
        final String fileName = "12";
        LabeledQRCode.of(title, label).withTempBase(QRCODE_TEMP_PATH)
                .toFile(fileName);
    }
}
